﻿using System;
using System.Text;
using System.Threading;
using CuteSprite.Eme.Data.CRM;
using HmFramework;
using HmFramework.Net;
using HmFramework.Net.Monitoring;
using HmFramework.Text;

namespace CuteSprite.Eme.MIS.Client
{
	/// <summary>Mis Client</summary>
	public class BsdMisClient : MisClient<BsdMisClient, BsdMisReadResponseAsyncOP,
		BsdUntaggedResponseSystemCodes, BsdUntaggedResponseSystemStatus, BsdUntaggedResponseSystemOptions,
		BsdUntaggedResponseConfigList, BsdUntaggedResponseConfigFile,
		BsdUntaggedResponseEntityList, BsdUntaggedResponseEntityListSerializer, BsdUntaggedResponseEntity, BsdUntaggedResponseFileStream>
	{
		#region -- 快件 --

		#region - method GrantExpressStaff -

		/// <summary>保存快件收件、派件员工信息</summary>
		/// <param name="category">快件业务类别</param>
		/// <param name="isReceiveStaff">是否收件员工</param>
		/// <param name="expressID">快件记录ID</param>
		/// <param name="ids">员工IDs</param>
		public void GrantExpressStaff(ExpressBusinessCategory category, Boolean isReceiveStaff, Int32 expressID, String ids)
		{
			ValidationHelper.ObjectDisposedCondition(Disposed, GetType().Name);
			ValidationHelper.InvalidOperationCondition(!IsConnected, "Not connected, you need to connect first.");
			ValidationHelper.InvalidOperationCondition(!IsAuthenticated, "Not authenticated, you need to authenticate first.");
			ValidationHelper.InvalidOperationCondition(IdleOP != null, "This command is not valid in IDLE state, you need stop idling before calling this command.");

			using (var op = new GrantExpressStaffAsyncOP(category, isReceiveStaff, expressID, ids))
			{
				using (var wait = new ManualResetEvent(false))
				{
					op.Completed += (asyncOP) =>
					{
						wait.Set();
					};
					if (!GrantExpressStaffAsync(op))
					{
						wait.Set();
					}
					wait.WaitOne();
					if (op.Error != null)
					{
						throw op.Error;
					}
				}
			}
		}

		#endregion

		#region - method GrantExpressStaffAsync -

		#region class GrantExpressStaffAsyncOP

		/// <summary>This class represents <see cref="MisClient.GrantExpressStaffAsync"/> asynchronous operation.</summary>
		private class GrantExpressStaffAsyncOP : CmdAsyncOP<GrantExpressStaffAsyncOP>
		{
			private ExpressBusinessCategory m_category;
			private Boolean m_isReceiveStaff;
			private Int32 m_expressID;
			private String m_ids;

			/// <summary>构造函数</summary>
			/// <param name="category"></param>
			/// <param name="isReceiveStaff"></param>
			/// <param name="expressID"></param>
			/// <param name="ids"></param>
			public GrantExpressStaffAsyncOP(ExpressBusinessCategory category, Boolean isReceiveStaff, Int32 expressID, String ids)
				: base(null)
			{
				m_category = category;
				m_isReceiveStaff = isReceiveStaff;
				m_expressID = expressID;
				m_ids = ids;
			}

			#region override method OnInitCmdLine

			/// <summary>Is called when we need to init command line info.</summary>
			/// <param name="client">TMisClient client.</param>
			protected override void OnInitCmdLine(BsdMisClient client)
			{
				Int64 idx = client.IncrementCommandIndex();

				StringBuilder command = new StringBuilder();
				command.Append(idx.ToString("d5"));
				command.Append(" GrantExpressStaff ");
				command.Append("" + (Int32)m_category);
				command.Append(" ");
				command.Append(m_isReceiveStaff ? "1" : "0");
				command.Append(" ");
				command.Append(m_expressID);
				command.Append(" ");
				command.Append(StringHelper.QuoteString(m_ids.IsNullOrWhiteSpace() ? " " : m_ids));
				command.Append("\r\n");

				var line = command.ToString();
				Byte[] cmdLine = client.CurrentEncoding.GetBytes(line);
				CmdLines.Add(new CmdLine(cmdLine, line.TrimEnd()));
			}

			#endregion
		}

		#endregion

		/// <summary>Executes GrantExpressStaff command.</summary>
		/// <param name="op">Asynchronous operation.</param>
		/// <returns>Returns true if aynchronous operation is pending (The <see cref="CmdAsyncOP{T}.CompletedAsync"/> event is raised upon completion of the operation).
		/// Returns false if operation completed synchronously.</returns>
		/// <exception cref="ObjectDisposedException">Is raised when this Object is disposed and and this method is accessed.</exception>
		/// <exception cref="InvalidOperationException">Is raised when Management client is not in valid state. For example 'not connected'.</exception>
		/// <exception cref="ArgumentNullException">Is raised when <b>op</b> is null reference.</exception>
		/// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
		private Boolean GrantExpressStaffAsync(GrantExpressStaffAsyncOP op)
		{
			ValidationHelper.ObjectDisposedCondition(Disposed, GetType().Name);
			ValidationHelper.InvalidOperationCondition(!IsConnected, "You must connect first.");
			ValidationHelper.InvalidOperationCondition(IdleOP != null, "This command is not valid in IDLE state, you need stop idling before calling this command.");
			ValidationHelper.ArgumentNull(op, "op");
			ValidationHelper.ArgumentCondition(op.State != AsyncOPState.WaitingForStart, "op", "Invalid argument '{0}' state, '{0}' must be in 'AsyncOPState.WaitingForStart' state.");
			return op.Start(this);
		}

		#endregion

		#region - method GetExpressStaff -

		/// <summary>获取快件的派件收件人员信息</summary>
		/// <param name="category">快件业务类别</param>
		/// <param name="isReceiveStaff">是否揽件人员</param>
		/// <param name="expressID">快件记录ID</param>
		/// <returns></returns>
		public String GetExpressStaff(ExpressBusinessCategory category, Boolean isReceiveStaff, Int32 expressID)
		{
			ValidationHelper.ArgumentCondition(expressID < 1, "无效的快件ID!");
			ValidationHelper.ObjectDisposedCondition(Disposed, GetType().Name);
			ValidationHelper.InvalidOperationCondition(!IsConnected, "Not connected, you need to connect first.");
			ValidationHelper.InvalidOperationCondition(!IsAuthenticated, "Not authenticated, you need to authenticate first.");
			ValidationHelper.InvalidOperationCondition(IdleOP != null, "This command is not valid in IDLE state, you need stop idling before calling this command.");

			String retVal = null;

			// Create callback. It is called for each untagged MIS server response.
			EventHandler<EventArgs<UntaggedResponseBase>> callback = delegate(Object sender, EventArgs<UntaggedResponseBase> e)
			{
				var response = (e.Arg as UntaggedResponseEntityFieldValue);
				if (response != null) { retVal = response.FieldValue; }
			};

			using (var op = new GetExpressStaffAsyncOP(callback, category, isReceiveStaff, expressID))
			{
				using (var wait = new ManualResetEvent(false))
				{
					op.Completed += (asyncOP) =>
					{
						//NetHelper.WriteLog("GetEntityFieldValue异步结束");
						wait.Set();
					};
					if (!GetExpressStaffAsync(op))
					{
						//NetHelper.WriteLog("GetEntityFieldValue同步结束");
						wait.Set();
					}
					wait.WaitOne();
					if (op.Error != null)
					{
						throw op.Error;
					}
				}
			}
			return retVal;
		}

		#endregion

		#region - method GetExpressStaffAsync -

		#region class GetExpressStaffAsyncOP

		/// <summary>This class represents <see cref="MisClient.GetExpressStaffAsync"/> asynchronous operation.</summary>
		private class GetExpressStaffAsyncOP : CmdAsyncOP<GetExpressStaffAsyncOP>
		{
			private ExpressBusinessCategory m_category;
			private Boolean m_isReceiveStaff;
			private Int32 m_expressID;

			/// <summary>Default constructor.</summary>
			/// <param name="callback">Optional callback to be called for each received untagged response.</param>
			/// <param name="isReceiveStaff"></param>
			/// <param name="expressID"></param>
			/// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
			public GetExpressStaffAsyncOP(EventHandler<EventArgs<UntaggedResponseBase>> callback, ExpressBusinessCategory category, Boolean isReceiveStaff, Int32 expressID)
				: base(callback)
			{
				m_category = category;
				m_isReceiveStaff = isReceiveStaff;
				m_expressID = expressID;
			}

			#region override method OnInitCmdLine

			/// <summary>Is called when we need to init command line info.</summary>
			/// <param name="client">TMisClient client.</param>
			protected override void OnInitCmdLine(BsdMisClient client)
			{
				Int64 idx = client.IncrementCommandIndex();

				StringBuilder command = new StringBuilder();
				command.Append(idx.ToString("d5"));
				command.Append(" GetExpressStaff ");
				command.Append("" + (Int32)m_category);
				command.Append(" ");
				command.Append(m_isReceiveStaff ? "1" : "0");
				command.Append(" ");
				command.Append(m_expressID);
				command.Append("\r\n");

				var line = command.ToString();
				Byte[] cmdLine = client.CurrentEncoding.GetBytes(line);
				CmdLines.Add(new CmdLine(cmdLine, line.TrimEnd()));
			}

			#endregion
		}

		#endregion

		/// <summary>Executes GetExpressStaff command.</summary>
		/// <param name="op">Asynchronous operation.</param>
		/// <returns>Returns true if aynchronous operation is pending (The <see cref="CmdAsyncOP{T}.CompletedAsync"/> event is raised upon completion of the operation).
		/// Returns false if operation completed synchronously.</returns>
		/// <exception cref="ObjectDisposedException">Is raised when this Object is disposed and and this method is accessed.</exception>
		/// <exception cref="InvalidOperationException">Is raised when Management client is not in valid state. For example 'not connected'.</exception>
		/// <exception cref="ArgumentNullException">Is raised when <b>op</b> is null reference.</exception>
		/// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
		private Boolean GetExpressStaffAsync(GetExpressStaffAsyncOP op)
		{
			ValidationHelper.ObjectDisposedCondition(Disposed, GetType().Name);
			ValidationHelper.InvalidOperationCondition(!IsConnected, "You must connect first.");
			ValidationHelper.InvalidOperationCondition(IdleOP != null, "This command is not valid in IDLE state, you need stop idling before calling this command.");
			ValidationHelper.ArgumentNull(op, "op");
			ValidationHelper.ArgumentCondition(op.State != AsyncOPState.WaitingForStart, "op", "Invalid argument '{0}' state, '{0}' must be in 'AsyncOPState.WaitingForStart' state.");
			return op.Start(this);
		}

		#endregion

		#region - method BatchUpdateExpressStatus -

		/// <summary>批量更新快件状态</summary>
		/// <param name="os"></param>
		/// <param name="isEconomyLine"></param>
		public void BatchUpdateExpressStatus(ExpressOperationStatus os, Boolean isEconomyLine)
		{
			ValidationHelper.ObjectDisposedCondition(Disposed, GetType().Name);
			ValidationHelper.InvalidOperationCondition(!IsConnected, "Not connected, you need to connect first.");
			ValidationHelper.InvalidOperationCondition(!IsAuthenticated, "Not authenticated, you need to authenticate first.");
			ValidationHelper.InvalidOperationCondition(IdleOP != null, "This command is not valid in IDLE state, you need stop idling before calling this command.");

			using (var op = new BatchUpdateExpressStatusAsyncOP((Int32)os, isEconomyLine))
			{
				using (var wait = new ManualResetEvent(false))
				{
					op.Completed += (asyncOP) =>
					{
						wait.Set();
					};
					if (!BatchUpdateExpressStatusAsync(op))
					{
						wait.Set();
					}
					wait.WaitOne();
					if (op.Error != null)
					{
						throw op.Error;
					}
				}
			}
		}

		#endregion

		#region - method BatchUpdateExpressStatusAsync -

		#region class BatchUpdateExpressStatusAsyncOP

		/// <summary>This class represents <see cref="MisClient.BatchUpdateExpressStatusAsync"/> asynchronous operation.</summary>
		private class BatchUpdateExpressStatusAsyncOP : CmdAsyncOP<BatchUpdateExpressStatusAsyncOP>
		{
			private Int32 m_os;
			private Boolean m_isEconomyLine;

			/// <summary>构造函数</summary>
			/// <param name="os"></param>
			/// <param name="isEconomyLine"></param>
			public BatchUpdateExpressStatusAsyncOP(Int32 os, Boolean isEconomyLine)
				: base(null)
			{
				m_os = os;
				m_isEconomyLine = isEconomyLine;
			}

			#region override method OnInitCmdLine

			/// <summary>Is called when we need to init command line info.</summary>
			/// <param name="client">TMisClient client.</param>
			protected override void OnInitCmdLine(BsdMisClient client)
			{
				Int64 idx = client.IncrementCommandIndex();

				StringBuilder command = new StringBuilder();
				command.Append(idx.ToString("d5"));
				command.Append(" BatchUpdateExpressStatus ");
				command.Append(m_os);
				command.Append(" ");
				command.Append(!m_isEconomyLine ? "0" : "1");
				command.Append("\r\n");

				var line = command.ToString();
				Byte[] cmdLine = client.CurrentEncoding.GetBytes(line);
				CmdLines.Add(new CmdLine(cmdLine, line.TrimEnd()));
			}

			#endregion
		}

		#endregion

		/// <summary>Executes BatchUpdateExpressStatus command.</summary>
		/// <param name="op">Asynchronous operation.</param>
		/// <returns>Returns true if aynchronous operation is pending (The <see cref="CmdAsyncOP{T}.CompletedAsync"/> event is raised upon completion of the operation).
		/// Returns false if operation completed synchronously.</returns>
		/// <exception cref="ObjectDisposedException">Is raised when this Object is disposed and and this method is accessed.</exception>
		/// <exception cref="InvalidOperationException">Is raised when Management client is not in valid state. For example 'not connected'.</exception>
		/// <exception cref="ArgumentNullException">Is raised when <b>op</b> is null reference.</exception>
		/// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
		private Boolean BatchUpdateExpressStatusAsync(BatchUpdateExpressStatusAsyncOP op)
		{
			ValidationHelper.ObjectDisposedCondition(Disposed, GetType().Name);
			ValidationHelper.InvalidOperationCondition(!IsConnected, "You must connect first.");
			ValidationHelper.InvalidOperationCondition(IdleOP != null, "This command is not valid in IDLE state, you need stop idling before calling this command.");
			ValidationHelper.ArgumentNull(op, "op");
			ValidationHelper.ArgumentCondition(op.State != AsyncOPState.WaitingForStart, "op", "Invalid argument '{0}' state, '{0}' must be in 'AsyncOPState.WaitingForStart' state.");
			return op.Start(this);
		}

		#endregion

		#region - method BatchUpdateExpressOperationStatus -

		/// <summary>批量修改快件状态的操作时间或操作说明</summary>
		/// <param name="ids"></param>
		/// <param name="opTime"></param>
		/// <param name="opDesc"></param>
		/// <param name="isEconomyLine"></param>
		public void BatchUpdateExpressOperationStatus(String ids, String opTime, String opDesc, Boolean isEconomyLine)
		{
			ValidationHelper.ArgumentNullOrEmpty(ids, "ids");
			ValidationHelper.ObjectDisposedCondition(Disposed, GetType().Name);
			ValidationHelper.InvalidOperationCondition(!IsConnected, "Not connected, you need to connect first.");
			ValidationHelper.InvalidOperationCondition(!IsAuthenticated, "Not authenticated, you need to authenticate first.");
			ValidationHelper.InvalidOperationCondition(IdleOP != null, "This command is not valid in IDLE state, you need stop idling before calling this command.");

			using (var op = new BatchUpdateExpressOperationStatusAsyncOP(ids, opTime, opDesc, isEconomyLine))
			{
				using (var wait = new ManualResetEvent(false))
				{
					op.Completed += (asyncOP) =>
					{
						wait.Set();
					};
					if (!BatchUpdateExpressOperationStatusAsync(op))
					{
						wait.Set();
					}
					wait.WaitOne();
					if (op.Error != null)
					{
						throw op.Error;
					}
				}
			}
		}

		#endregion

		#region - method BatchUpdateExpressOperationStatusAsync -

		#region class BatchUpdateExpressOperationStatusAsyncOP

		/// <summary>This class represents <see cref="MisClient.BatchUpdateExpressOperationStatusAsync"/> asynchronous operation.</summary>
		private class BatchUpdateExpressOperationStatusAsyncOP : CmdAsyncOP<BatchUpdateExpressOperationStatusAsyncOP>
		{
			private String m_ids;
			private String m_opTime;
			private String m_opDesc;
			private Boolean m_isEconomyLine;

			/// <summary>构造函数</summary>
			/// <param name="ids"></param>
			/// <param name="opTime"></param>
			/// <param name="opDesc"></param>
			/// <param name="isEconomyLine"></param>
			public BatchUpdateExpressOperationStatusAsyncOP(String ids, String opTime, String opDesc, Boolean isEconomyLine)
				: base(null)
			{
				m_ids = ids;
				m_opTime = opTime;
				m_opDesc = opDesc;
				m_isEconomyLine = isEconomyLine;
			}

			#region override method OnInitCmdLine

			/// <summary>Is called when we need to init command line info.</summary>
			/// <param name="client">TMisClient client.</param>
			protected override void OnInitCmdLine(BsdMisClient client)
			{
				Int64 idx = client.IncrementCommandIndex();

				StringBuilder command = new StringBuilder();
				command.Append(idx.ToString("d5"));
				command.Append(" BatchUpdateExpressOperationStatus ");
				command.Append(StringHelper.QuoteString(m_ids));
				command.Append(" ");
				command.Append(StringHelper.QuoteString(m_opTime));
				command.Append(" ");
				command.Append(StringHelper.QuoteString(m_opDesc));
				command.Append(" ");
				command.Append(StringHelper.QuoteString(!m_isEconomyLine ? "0" : "1"));
				command.Append("\r\n");

				var line = command.ToString();
				Byte[] cmdLine = client.CurrentEncoding.GetBytes(line);
				CmdLines.Add(new CmdLine(cmdLine, line.TrimEnd()));
			}

			#endregion
		}

		#endregion

		/// <summary>Executes BatchUpdateExpressOperationStatus command.</summary>
		/// <param name="op">Asynchronous operation.</param>
		/// <returns>Returns true if aynchronous operation is pending (The <see cref="CmdAsyncOP{T}.CompletedAsync"/> event is raised upon completion of the operation).
		/// Returns false if operation completed synchronously.</returns>
		/// <exception cref="ObjectDisposedException">Is raised when this Object is disposed and and this method is accessed.</exception>
		/// <exception cref="InvalidOperationException">Is raised when Management client is not in valid state. For example 'not connected'.</exception>
		/// <exception cref="ArgumentNullException">Is raised when <b>op</b> is null reference.</exception>
		/// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
		private Boolean BatchUpdateExpressOperationStatusAsync(BatchUpdateExpressOperationStatusAsyncOP op)
		{
			ValidationHelper.ObjectDisposedCondition(Disposed, GetType().Name);
			ValidationHelper.InvalidOperationCondition(!IsConnected, "You must connect first.");
			ValidationHelper.InvalidOperationCondition(IdleOP != null, "This command is not valid in IDLE state, you need stop idling before calling this command.");
			ValidationHelper.ArgumentNull(op, "op");
			ValidationHelper.ArgumentCondition(op.State != AsyncOPState.WaitingForStart, "op", "Invalid argument '{0}' state, '{0}' must be in 'AsyncOPState.WaitingForStart' state.");
			return op.Start(this);
		}

		#endregion

		#region - method GetExpressLastStatus -

		/// <summary>根据快件ID获取该快件的最新状态</summary>
		/// <param name="expressid">快件id</param>
		/// <param name="isEconomyLine">是否经济线快件</param>
		/// <returns>XML序列化后的实体</returns>
		public ExpressStatus GetExpressLastStatus(Int32 expressid, Boolean isEconomyLine)
		{
			// 可以为空值，以判断字段是否为空
			//ValidationHelper.ArgumentNull(value, "value");
			ValidationHelper.ObjectDisposedCondition(Disposed, GetType().Name);
			ValidationHelper.InvalidOperationCondition(!IsConnected, "Not connected, you need to connect first.");
			ValidationHelper.InvalidOperationCondition(!IsAuthenticated, "Not authenticated, you need to authenticate first.");
			ValidationHelper.InvalidOperationCondition(IdleOP != null, "This command is not valid in IDLE state, you need stop idling before calling this command.");

			BsdUntaggedResponseEntity response = null;

			// Create callback. It is called for each untagged MIS server response.
			EventHandler<EventArgs<UntaggedResponseBase>> callback = delegate(Object sender, EventArgs<UntaggedResponseBase> e)
			{
				response = e.Arg as BsdUntaggedResponseEntity;
			};

			using (var op = new GetExpressLastStatusAsyncOP(callback, expressid, isEconomyLine))
			{
				using (var wait = new ManualResetEvent(false))
				{
					op.Completed += (asyncOP) =>
					{
						wait.Set();
					};
					if (!GetExpressLastStatusAsync(op))
					{
						wait.Set();
					}
					wait.WaitOne();
					if (op.Error != null)
					{
						throw op.Error;
					}
				}
			}
			if (response != null && !response.EntityXml.IsNullOrWhiteSpace())
			{
				return ExpressStatus.FromXml(response.EntityXml);
			}

			return null;
		}

		#endregion

		#region - method GetExpressLastStatusAsync -

		#region class GetExpressLastStatusAsyncOP

		/// <summary>This class represents <see cref="MisClient.GetExpressLastStatusAsync"/> asynchronous operation.</summary>
		private class GetExpressLastStatusAsyncOP : CmdAsyncOP<GetExpressLastStatusAsyncOP>
		{
			private Int32 m_expressid;
			private Boolean m_isEconomyLine;

			/// <summary>Default constructor.</summary>
			/// <param name="callback">Optional callback to be called for each received untagged response.</param>
			/// <param name="expressid"></param>
			/// <param name="isEconomyLine"></param>
			/// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
			public GetExpressLastStatusAsyncOP(EventHandler<EventArgs<UntaggedResponseBase>> callback, Int32 expressid, Boolean isEconomyLine)
				: base(callback)
			{
				m_expressid = expressid;
				m_isEconomyLine = isEconomyLine;
			}

			#region override method OnInitCmdLine

			/// <summary>Is called when we need to init command line info.</summary>
			/// <param name="client">MIS client.</param>
			protected override void OnInitCmdLine(BsdMisClient client)
			{
				Int64 idx = client.IncrementCommandIndex();

				StringBuilder command = new StringBuilder();
				command.Append(idx.ToString("d5"));
				command.Append(" GetExpressLastStatus ");
				command.Append(m_expressid);
				command.Append(" ");
				command.Append(!m_isEconomyLine ? "0" : "1");
				command.Append("\r\n");

				var line = command.ToString();
				Byte[] cmdLine = client.CurrentEncoding.GetBytes(line);
				CmdLines.Add(new CmdLine(cmdLine, line.TrimEnd()));
			}

			#endregion
		}

		#endregion

		/// <summary>Executes GetExpressLastStatus command</summary>
		/// <param name="op">Asynchronous operation.</param>
		/// <returns>Returns true if aynchronous operation is pending (The <see cref="CmdAsyncOP{T}.CompletedAsync"/> event is raised upon completion of the operation).
		/// Returns false if operation completed synchronously.</returns>
		/// <exception cref="ObjectDisposedException">Is raised when this Object is disposed and and this method is accessed.</exception>
		/// <exception cref="InvalidOperationException">Is raised when Management client is not in valid state. For example 'not connected'.</exception>
		/// <exception cref="ArgumentNullException">Is raised when <b>op</b> is null reference.</exception>
		/// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
		private Boolean GetExpressLastStatusAsync(GetExpressLastStatusAsyncOP op)
		{
			ValidationHelper.ObjectDisposedCondition(Disposed, GetType().Name);
			ValidationHelper.InvalidOperationCondition(!IsConnected, "You must connect first.");
			ValidationHelper.InvalidOperationCondition(!IsAuthenticated, "Not authenticated, you need to authenticate first.");
			ValidationHelper.InvalidOperationCondition(IdleOP != null, "This command is not valid in IDLE state, you need stop idling before calling this command.");
			ValidationHelper.ArgumentNull(op, "op");
			ValidationHelper.ArgumentCondition(op.State != AsyncOPState.WaitingForStart, "op", "Invalid argument '{0}' state, '{0}' must be in 'AsyncOPState.WaitingForStart' state.");
			return op.Start(this);
		}

		#endregion

		#region - method CheckExpressExist -

		/// <summary>根据运单号码检查运单是否已经存在</summary>
		/// <param name="category">运单业务类别</param>
		/// <param name="expressNo">运单号</param>
		/// <param name="excludedID">排除运单号</param>
		/// <returns></returns>
		public Boolean CheckExpressExist(ExpressBusinessCategory category, String expressNo, Int32 excludedID)
		{
			ValidationHelper.ArgumentNullOrEmpty(expressNo, "expressNo");
			ValidationHelper.ObjectDisposedCondition(Disposed, GetType().Name);
			ValidationHelper.InvalidOperationCondition(!IsConnected, "Not connected, you need to connect first.");
			ValidationHelper.InvalidOperationCondition(!IsAuthenticated, "Not authenticated, you need to authenticate first.");
			ValidationHelper.InvalidOperationCondition(IdleOP != null, "This command is not valid in IDLE state, you need stop idling before calling this command.");

			String retVal = null;

			// Create callback. It is called for each untagged MIS server response.
			EventHandler<EventArgs<UntaggedResponseBase>> callback = delegate(Object sender, EventArgs<UntaggedResponseBase> e)
			{
				var response = (e.Arg as UntaggedResponseEntityFieldValue);
				if (response != null) { retVal = response.FieldValue; }
			};

			using (var op = new CheckExpressExistAsyncOP(callback, category, expressNo, excludedID))
			{
				using (var wait = new ManualResetEvent(false))
				{
					op.Completed += (asyncOP) =>
					{
						//NetHelper.WriteLog("GetEntityFieldValue异步结束");
						wait.Set();
					};
					if (!CheckExpressExistAsync(op))
					{
						//NetHelper.WriteLog("GetEntityFieldValue同步结束");
						wait.Set();
					}
					wait.WaitOne();
					if (op.Error != null)
					{
						throw op.Error;
					}
				}
			}

			Int32 ret = 0;
			Int32.TryParse(retVal, out ret);
			return ret != 0;
		}

		#endregion

		#region - method CheckExpressExistAsync -

		#region class CheckExpressExistAsyncOP

		/// <summary>This class represents <see cref="MisClient.CheckExpressExistAsync"/> asynchronous operation.</summary>
		private class CheckExpressExistAsyncOP : CmdAsyncOP<CheckExpressExistAsyncOP>
		{
			private ExpressBusinessCategory m_category;
			private String m_expressNo;
			private Int32 m_excludedID;

			/// <summary>Default constructor.</summary>
			/// <param name="callback">Optional callback to be called for each received untagged response.</param>
			/// <param name="category"></param>
			/// <param name="expressNo"></param>
			/// <param name="excludedID"></param>
			/// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
			public CheckExpressExistAsyncOP(EventHandler<EventArgs<UntaggedResponseBase>> callback, ExpressBusinessCategory category, String expressNo, Int32 excludedID)
				: base(callback)
			{
				m_category = category;
				m_expressNo = expressNo;
				m_excludedID = excludedID;
			}

			#region override method OnInitCmdLine

			/// <summary>Is called when we need to init command line info.</summary>
			/// <param name="client">TMisClient client.</param>
			protected override void OnInitCmdLine(BsdMisClient client)
			{
				Int64 idx = client.IncrementCommandIndex();

				StringBuilder command = new StringBuilder();
				command.Append(idx.ToString("d5"));
				command.Append(" CheckExpressExist ");
				command.Append("" + (Int32)m_category);
				command.Append(" ");
				command.Append(StringHelper.QuoteString(m_expressNo));
				command.Append(" ");
				command.Append(m_excludedID);
				command.Append("\r\n");

				var line = command.ToString();
				Byte[] cmdLine = client.CurrentEncoding.GetBytes(line);
				CmdLines.Add(new CmdLine(cmdLine, line.TrimEnd()));
			}

			#endregion
		}

		#endregion

		/// <summary>Executes CheckExpressExist command.</summary>
		/// <param name="op">Asynchronous operation.</param>
		/// <returns>Returns true if aynchronous operation is pending (The <see cref="CmdAsyncOP{T}.CompletedAsync"/> event is raised upon completion of the operation).
		/// Returns false if operation completed synchronously.</returns>
		/// <exception cref="ObjectDisposedException">Is raised when this Object is disposed and and this method is accessed.</exception>
		/// <exception cref="InvalidOperationException">Is raised when Management client is not in valid state. For example 'not connected'.</exception>
		/// <exception cref="ArgumentNullException">Is raised when <b>op</b> is null reference.</exception>
		/// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
		private Boolean CheckExpressExistAsync(CheckExpressExistAsyncOP op)
		{
			ValidationHelper.ObjectDisposedCondition(Disposed, GetType().Name);
			ValidationHelper.InvalidOperationCondition(!IsConnected, "You must connect first.");
			ValidationHelper.InvalidOperationCondition(IdleOP != null, "This command is not valid in IDLE state, you need stop idling before calling this command.");
			ValidationHelper.ArgumentNull(op, "op");
			ValidationHelper.ArgumentCondition(op.State != AsyncOPState.WaitingForStart, "op", "Invalid argument '{0}' state, '{0}' must be in 'AsyncOPState.WaitingForStart' state.");
			return op.Start(this);
		}

		#endregion

		#region - method MakeExpressNextNo -

		/// <summary>自动产生运单号码</summary>
		/// <param name="category">运单业务类别</param>
		/// <returns></returns>
		public String MakeExpressNextNo(ExpressBusinessCategory category)
		{
			ValidationHelper.ObjectDisposedCondition(Disposed, GetType().Name);
			ValidationHelper.InvalidOperationCondition(!IsConnected, "Not connected, you need to connect first.");
			ValidationHelper.InvalidOperationCondition(!IsAuthenticated, "Not authenticated, you need to authenticate first.");
			ValidationHelper.InvalidOperationCondition(IdleOP != null, "This command is not valid in IDLE state, you need stop idling before calling this command.");

			String retVal = null;

			// Create callback. It is called for each untagged MIS server response.
			EventHandler<EventArgs<UntaggedResponseBase>> callback = delegate(Object sender, EventArgs<UntaggedResponseBase> e)
			{
				var response = (e.Arg as UntaggedResponseEntityFieldValue);
				if (response != null) { retVal = response.FieldValue; }
			};

			using (var op = new MakeExpressNextNoAsyncOP(callback, category))
			{
				using (var wait = new ManualResetEvent(false))
				{
					op.Completed += (asyncOP) =>
					{
						//NetHelper.WriteLog("GetEntityFieldValue异步结束");
						wait.Set();
					};
					if (!MakeExpressNextNoAsync(op))
					{
						//NetHelper.WriteLog("GetEntityFieldValue同步结束");
						wait.Set();
					}
					wait.WaitOne();
					if (op.Error != null)
					{
						throw op.Error;
					}
				}
			}

			return retVal;
		}

		#endregion

		#region - method MakeExpressNextNoAsync -

		#region class MakeExpressNextNoAsyncOP

		/// <summary>This class represents <see cref="MisClient.MakeExpressNextNoAsync"/> asynchronous operation.</summary>
		private class MakeExpressNextNoAsyncOP : CmdAsyncOP<MakeExpressNextNoAsyncOP>
		{
			private ExpressBusinessCategory m_category;

			/// <summary>Default constructor.</summary>
			/// <param name="callback">Optional callback to be called for each received untagged response.</param>
			/// <param name="category"></param>
			/// <param name="expressNo"></param>
			/// <param name="excludedID"></param>
			/// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
			public MakeExpressNextNoAsyncOP(EventHandler<EventArgs<UntaggedResponseBase>> callback, ExpressBusinessCategory category)
				: base(callback)
			{
				m_category = category;
			}

			#region override method OnInitCmdLine

			/// <summary>Is called when we need to init command line info.</summary>
			/// <param name="client">TMisClient client.</param>
			protected override void OnInitCmdLine(BsdMisClient client)
			{
				Int64 idx = client.IncrementCommandIndex();

				StringBuilder command = new StringBuilder();
				command.Append(idx.ToString("d5"));
				command.Append(" MakeExpressNextNo ");
				command.Append("" + (Int32)m_category);
				command.Append("\r\n");

				var line = command.ToString();
				Byte[] cmdLine = client.CurrentEncoding.GetBytes(line);
				CmdLines.Add(new CmdLine(cmdLine, line.TrimEnd()));
			}

			#endregion
		}

		#endregion

		/// <summary>Executes MakeExpressNextNo command.</summary>
		/// <param name="op">Asynchronous operation.</param>
		/// <returns>Returns true if aynchronous operation is pending (The <see cref="CmdAsyncOP{T}.CompletedAsync"/> event is raised upon completion of the operation).
		/// Returns false if operation completed synchronously.</returns>
		/// <exception cref="ObjectDisposedException">Is raised when this Object is disposed and and this method is accessed.</exception>
		/// <exception cref="InvalidOperationException">Is raised when Management client is not in valid state. For example 'not connected'.</exception>
		/// <exception cref="ArgumentNullException">Is raised when <b>op</b> is null reference.</exception>
		/// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
		private Boolean MakeExpressNextNoAsync(MakeExpressNextNoAsyncOP op)
		{
			ValidationHelper.ObjectDisposedCondition(Disposed, GetType().Name);
			ValidationHelper.InvalidOperationCondition(!IsConnected, "You must connect first.");
			ValidationHelper.InvalidOperationCondition(IdleOP != null, "This command is not valid in IDLE state, you need stop idling before calling this command.");
			ValidationHelper.ArgumentNull(op, "op");
			ValidationHelper.ArgumentCondition(op.State != AsyncOPState.WaitingForStart, "op", "Invalid argument '{0}' state, '{0}' must be in 'AsyncOPState.WaitingForStart' state.");
			return op.Start(this);
		}

		#endregion

		#region - method BatchUpdateCustomerSelfStatus -

		/// <summary>批量更改用户自主下单记录的已揽件状态</summary>
		/// <param name="ids"></param>
		public void BatchUpdateCustomerSelfStatus(String ids)
		{
			ValidationHelper.ArgumentNullOrEmpty(ids, "ids");
			ValidationHelper.ObjectDisposedCondition(Disposed, GetType().Name);
			ValidationHelper.InvalidOperationCondition(!IsConnected, "Not connected, you need to connect first.");
			ValidationHelper.InvalidOperationCondition(!IsAuthenticated, "Not authenticated, you need to authenticate first.");
			ValidationHelper.InvalidOperationCondition(IdleOP != null, "This command is not valid in IDLE state, you need stop idling before calling this command.");

			using (var op = new BatchUpdateCustomerSelfStatusAsyncOP(ids))
			{
				using (var wait = new ManualResetEvent(false))
				{
					op.Completed += (asyncOP) =>
					{
						wait.Set();
					};
					if (!BatchUpdateCustomerSelfStatusAsync(op))
					{
						wait.Set();
					}
					wait.WaitOne();
					if (op.Error != null)
					{
						throw op.Error;
					}
				}
			}
		}

		#endregion

		#region - method BatchUpdateCustomerSelfStatusAsync -

		#region class BatchUpdateCustomerSelfStatusAsyncOP

		/// <summary>This class represents <see cref="MisClient.BatchUpdateExpressOperationStatusAsync"/> asynchronous operation.</summary>
		private class BatchUpdateCustomerSelfStatusAsyncOP : CmdAsyncOP<BatchUpdateCustomerSelfStatusAsyncOP>
		{
			private String m_ids;

			/// <summary>构造函数</summary>
			/// <param name="ids"></param>
			public BatchUpdateCustomerSelfStatusAsyncOP(String ids)
				: base(null)
			{
				m_ids = ids;
			}

			#region override method OnInitCmdLine

			/// <summary>Is called when we need to init command line info.</summary>
			/// <param name="client">TMisClient client.</param>
			protected override void OnInitCmdLine(BsdMisClient client)
			{
				Int64 idx = client.IncrementCommandIndex();

				StringBuilder command = new StringBuilder();
				command.Append(idx.ToString("d5"));
				command.Append(" BatchUpdateCustomerSelfStatus ");
				command.Append(StringHelper.QuoteString(m_ids));
				command.Append("\r\n");

				var line = command.ToString();
				Byte[] cmdLine = client.CurrentEncoding.GetBytes(line);
				CmdLines.Add(new CmdLine(cmdLine, line.TrimEnd()));
			}

			#endregion
		}

		#endregion

		/// <summary>Executes BatchUpdateCustomerSelfStatus command.</summary>
		/// <param name="op">Asynchronous operation.</param>
		/// <returns>Returns true if aynchronous operation is pending (The <see cref="CmdAsyncOP{T}.CompletedAsync"/> event is raised upon completion of the operation).
		/// Returns false if operation completed synchronously.</returns>
		/// <exception cref="ObjectDisposedException">Is raised when this Object is disposed and and this method is accessed.</exception>
		/// <exception cref="InvalidOperationException">Is raised when Management client is not in valid state. For example 'not connected'.</exception>
		/// <exception cref="ArgumentNullException">Is raised when <b>op</b> is null reference.</exception>
		/// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
		private Boolean BatchUpdateCustomerSelfStatusAsync(BatchUpdateCustomerSelfStatusAsyncOP op)
		{
			ValidationHelper.ObjectDisposedCondition(Disposed, GetType().Name);
			ValidationHelper.InvalidOperationCondition(!IsConnected, "You must connect first.");
			ValidationHelper.InvalidOperationCondition(IdleOP != null, "This command is not valid in IDLE state, you need stop idling before calling this command.");
			ValidationHelper.ArgumentNull(op, "op");
			ValidationHelper.ArgumentCondition(op.State != AsyncOPState.WaitingForStart, "op", "Invalid argument '{0}' state, '{0}' must be in 'AsyncOPState.WaitingForStart' state.");
			return op.Start(this);
		}

		#endregion

		#endregion

		#region -- 结算 --

		#region - method BatchUpdateSettlements -

		/// <summary>批量更新快件状态</summary>
		/// <param name="startDate"></param>
		/// <param name="endDate"></param>
		public void BatchUpdateSettlements(DateTime startDate, DateTime endDate)
		{
			ValidationHelper.ObjectDisposedCondition(Disposed, GetType().Name);
			ValidationHelper.InvalidOperationCondition(!IsConnected, "Not connected, you need to connect first.");
			ValidationHelper.InvalidOperationCondition(!IsAuthenticated, "Not authenticated, you need to authenticate first.");
			ValidationHelper.InvalidOperationCondition(IdleOP != null, "This command is not valid in IDLE state, you need stop idling before calling this command.");

			using (var op = new BatchUpdateSettlementsAsyncOP(startDate, endDate))
			{
				using (var wait = new ManualResetEvent(false))
				{
					op.Completed += (asyncOP) =>
					{
						wait.Set();
					};
					if (!BatchUpdateSettlementsAsync(op))
					{
						wait.Set();
					}
					wait.WaitOne();
					if (op.Error != null)
					{
						throw op.Error;
					}
				}
			}
		}

		#endregion

		#region - method BatchUpdateSettlementsAsync -

		#region class BatchUpdateSettlementsAsyncOP

		/// <summary>This class represents <see cref="MisClient.BatchUpdateSettlementsAsync"/> asynchronous operation.</summary>
		private class BatchUpdateSettlementsAsyncOP : CmdAsyncOP<BatchUpdateSettlementsAsyncOP>
		{
			private DateTime m_startDate;
			private DateTime m_endDate;

			/// <summary>构造函数</summary>
			/// <param name="os"></param>
			/// <param name="isEconomyLine"></param>
			public BatchUpdateSettlementsAsyncOP(DateTime startDate, DateTime endDate)
				: base(null)
			{
				m_startDate = startDate;
				m_endDate = endDate;
			}

			#region override method OnInitCmdLine

			/// <summary>Is called when we need to init command line info.</summary>
			/// <param name="client">TMisClient client.</param>
			protected override void OnInitCmdLine(BsdMisClient client)
			{
				Int64 idx = client.IncrementCommandIndex();

				StringBuilder command = new StringBuilder();
				command.Append(idx.ToString("d5"));
				command.Append(" BatchUpdateSettlements ");
				command.Append(StringHelper.QuoteString("{0:yyyy-MM-dd 00:00:00}".FormatWith(m_startDate)));
				command.Append(" ");
				command.Append(StringHelper.QuoteString("{0:yyyy-MM-dd 00:00:00}".FormatWith(m_endDate)));
				command.Append("\r\n");
				var line = command.ToString();
				Byte[] cmdLine = client.CurrentEncoding.GetBytes(line);
				CmdLines.Add(new CmdLine(cmdLine, line.TrimEnd()));
			}

			#endregion
		}

		#endregion

		/// <summary>Executes BatchUpdateSettlements command.</summary>
		/// <param name="op">Asynchronous operation.</param>
		/// <returns>Returns true if aynchronous operation is pending (The <see cref="CmdAsyncOP{T}.CompletedAsync"/> event is raised upon completion of the operation).
		/// Returns false if operation completed synchronously.</returns>
		/// <exception cref="ObjectDisposedException">Is raised when this Object is disposed and and this method is accessed.</exception>
		/// <exception cref="InvalidOperationException">Is raised when Management client is not in valid state. For example 'not connected'.</exception>
		/// <exception cref="ArgumentNullException">Is raised when <b>op</b> is null reference.</exception>
		/// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
		private Boolean BatchUpdateSettlementsAsync(BatchUpdateSettlementsAsyncOP op)
		{
			ValidationHelper.ObjectDisposedCondition(Disposed, GetType().Name);
			ValidationHelper.InvalidOperationCondition(!IsConnected, "You must connect first.");
			ValidationHelper.InvalidOperationCondition(IdleOP != null, "This command is not valid in IDLE state, you need stop idling before calling this command.");
			ValidationHelper.ArgumentNull(op, "op");
			ValidationHelper.ArgumentCondition(op.State != AsyncOPState.WaitingForStart, "op", "Invalid argument '{0}' state, '{0}' must be in 'AsyncOPState.WaitingForStart' state.");
			return op.Start(this);
		}

		#endregion

		#endregion
	}
}